#include "widget.h"
#include "mycombobox.h"
#include "./ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui        (new Ui::Widget       )
    , serialPort(new QSerialPort(this))
    , timer     (new QTimer     (this))
    , nowTime   (new QTimer     (this))
    , tcpServer (new QTcpServer (this))
    , udpSocket (new QUdpSocket (this))
{
    ui->setupUi(this);

    nowTime->start(1000);

    //窗口子控件自适应大小
    this->setLayout(ui->gridLayout_ALL);

    //设置comboBox_BaudR的默认值
    ui->comboBox_BaudR->setCurrentIndex(5);
    //设置默认勾选自动发送二进制组包
    ui->checkBox_AutoSendBin->setChecked(true);
    //设置两个“发送”键在未打开串口或网络调试助手时默认为禁用
    ui->pushButton_SerialSend->setEnabled(false);
    ui->pushButton_NetSend->setEnabled(false);
    //设置网络调试助手的断开键与断开选择框在未开始监听时禁用
    ui->comboBox_Client->setEnabled(false);
    ui->pushButton_DisconnectClient->setEnabled(false);

    //程序启动前获取系统当前时间
    Update_labelTime();
    //刷新可用串口号
    refresh_SerialPorts();
    //刷新可用IP地址
    reflash_IP_Port();

    // 关联 serialPort 的 readyread 信号与 Serial_readyToRead         槽函数，实现串口信息的读取
    connect(serialPort, &QSerialPort::readyRead, this, &Widget::Serial_readyToRead);
    // 关联 timer      的 timeout   信号与 on_pushButton_Send_clicked 槽函数，实现串口的定时发送
    connect(timer  , &QTimer::timeout,[=](){on_pushButton_SerialSend_clicked();});
    // 关联 NowTime    的 timeout   信号与 Update_labelTime           槽函数，实现实时时间刷新
    connect(nowTime, &QTimer::timeout,[=](){Update_labelTime();});
    // 关联 comboBox   的showPopup 下拉列表信号与 refreshSerialPorts 槽函数，   实现可用串口号的刷新
    connect(ui->comboBox_SerialPort, &myComboBox::refreshPorts,this, &Widget::refresh_SerialPorts);
    // 关联 comboBox   的showPopup 下拉列表信号与 refreshSerialPorts 槽函数，   实现可用串口号的刷新
    connect(ui->comboBox_IP_Addr   , &myComboBox::refreshPorts,this, &Widget::reflash_IP_Port);
    // 关联 tcpServer  的 newConnection   信号与 New_Connect        槽函数，   实现与TCP客户端的连接
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(New_Connect()));
    // 关联 tcpServer  的 newConnection   信号与 New_Connect        槽函数，   实现UDP的连接
    connect(udpSocket, SIGNAL(readyRead()), this, SLOT(Net_readyToRead_UDP()));
}

Widget::~Widget()
{
    delete ui;
}

/*网络调试助手*/
//网口连接
void Widget::New_Connect(){
    if (ui->comboBox_comProtocol->currentText() == "TCP") {
        if(tcpServer->hasPendingConnections()){
            QTcpSocket *clientSocket  = tcpServer->nextPendingConnection();
            if (clientSocket) {
                ui->textEdit_Network->append("客户端IP地址：" + clientSocket->peerAddress().toString() + "\n客户端端口号：" +
                                             QString::number(clientSocket->peerPort()));

                // 构造客户端标识，并添加到comboBox_Client
                QString clientKey = clientSocket->peerAddress().toString() + ":" +
                                    QString::number(clientSocket->peerPort());
                clientMap.insert(clientKey, clientSocket);
                ui->comboBox_Client->addItem(clientKey);

                // 关联clientSocket的readyRead信号与Net_readyToRead_TCP槽函数，实现接收客户端信息的功能
                connect(clientSocket, SIGNAL(readyRead()), this, SLOT(Net_readyToRead_TCP()));
                // 关联clientSocket的stateChanged信号与stateChanged_Handler槽函数，实现连接状态提醒的功能
                connect(clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
                        this, SLOT  (stateChanged_Handler(QAbstractSocket::SocketState)));
            }
        }
    }
}

//TCP网口接收
void Widget::Net_readyToRead_TCP(){
    if (ui->comboBox_comProtocol->currentText() == "TCP") {
        if(ui->checkBox_getReceiveTime->checkState() == Qt::Checked){
            ui->textEdit_Network->append(QDateTime::currentDateTime().toString("【yyyy-MM-dd HH:mm:ss.zzz】"));
        }

        QTcpSocket *tmpSock = qobject_cast<QTcpSocket *>(sender());
        if (!tmpSock) return;

        // 读取原始二进制数据
        QByteArray rawData = tmpSock->readAll();
        PositionData data;
        data.longitude = -1;
        data.latitude = -1;

        // 尝试解析二进制组包（判断是否为0xAABB开头）
        bool isBinaryPacket = false;
        if (rawData.size() >= 2) { // 至少包含2字节识别字
            QDataStream stream(&rawData, QIODevice::ReadOnly);
            stream.setByteOrder(QDataStream::BigEndian); // 网络字节序
            quint16 identifier;
            stream >> identifier;

            if (identifier == 0xAABB) { // 匹配指定包头
                isBinaryPacket = true;
                // 检查完整包长度（19字节）
                if (rawData.size() >= 19) {
                    double lon, lat;
                    stream >> lon >> lat; // 解析经度、纬度
                    char reserve;
                    stream.readRawData(&reserve, 1); // 忽略保留位

                    data.longitude = lon;
                    data.latitude = lat;
                    data.timestamp = QDateTime::currentDateTime();
                    ui->textEdit_Network->append("TCP二进制组包解包成功：经度=" + QString::number(lon, 'f', 5) + "，纬度=" + QString::number(lat, 'f', 5));
                } else {
                    ui->textEdit_Network->append("TCP二进制组包不完整（需19字节，实际" + QString::number(rawData.size()) + "字节）");
                }
            }
        }

        // 若不是指定二进制组包，尝试解析文本格式数据
        if (!isBinaryPacket) {
            // 尝试以字符串形式显示
            QString textData = QString::fromUtf8(rawData);
            if (!textData.isEmpty()) {
                // 尝试解析文本格式数据
                PositionData parsedData = DataPacket_parsing(textData);
                if (parsedData.longitude != -1 && parsedData.latitude != -1) {
                    data = parsedData;
                    ui->textEdit_Network->append("TCP客户端（文本数据解析成功）：经度=" + QString::number(data.longitude, 'f', 5) + "，纬度=" + QString::number(data.latitude, 'f', 5));
                } else {
                    // 纯二进制非文本数据，以十六进制显示
                    textData = "0x" + rawData.toHex(' ').toUpper();
                    ui->textEdit_Network->append("TCP客户端（原始数据）：" + textData);
                }
            } else {
                // 纯二进制非文本数据，以十六进制显示
                textData = "0x" + rawData.toHex(' ').toUpper();
                ui->textEdit_Network->append("TCP客户端（原始数据）：" + textData);
            }
        }

        // 解析有效时执行后续操作
        if (data.longitude != -1 && data.latitude != -1) {
            data.source = PositionData::Network;
            positionCache.append(data);
            ui->lineEdit_longitude->setText(QString::number(data.longitude, 'f', 5));
            ui->lineEdit_latitude->setText(QString::number(data.latitude, 'f', 5));
            Network_To_Serial(data);
        }
    }
}

//UDP网口接收
void Widget::Net_readyToRead_UDP()
{
    if (ui->comboBox_comProtocol->currentText() == "UDP") {
        if (ui->checkBox_getReceiveTime->checkState() == Qt::Checked) {
            ui->textEdit_Network->append(QDateTime::currentDateTime().toString("【yyyy-MM-dd HH:mm:ss.zzz】"));
        }

        QHostAddress senderAddress;
        quint16 senderPort;
        qint64 availableSize = udpSocket->pendingDatagramSize();
        QByteArray rawData(availableSize, 0);
        qint64 len = udpSocket->readDatagram(rawData.data(), rawData.size(), &senderAddress, &senderPort);

        if (len > 0) {
            PositionData data;
            data.longitude = -1;
            data.latitude = -1;
            bool isBinaryPacket = false;

            // 尝试解析二进制组包（判断是否为0xAABB开头）
            if (len >= 2) { // 至少包含2字节识别字
                QDataStream stream(&rawData, QIODevice::ReadOnly);
                stream.setByteOrder(QDataStream::BigEndian); // 网络字节序
                quint16 identifier;
                stream >> identifier;

                if (identifier == 0xAABB) { // 匹配指定包头
                    isBinaryPacket = true;
                    // 检查完整包长度（2+8+8+1=19字节）
                    if (len >= 19) {
                        double lon, lat;
                        stream >> lon >> lat; // 解析经度、纬度
                        char reserve;
                        stream.readRawData(&reserve, 1); // 忽略保留位

                        data.longitude = lon;
                        data.latitude = lat;
                        data.timestamp = QDateTime::currentDateTime();
                        ui->textEdit_Network->append("UDP客户端 " + senderAddress.toString() + ":"
                                                     + QString::number(senderPort) + "（二进制组包解包成功）：经度="
                                                     + QString::number(lon, 'f', 5) + "，纬度=" + QString::number(lat, 'f', 5));
                    } else {
                        ui->textEdit_Network->append("UDP客户端 " + senderAddress.toString() + ":" + QString::number(senderPort)
                                                     + "（二进制组包不完整，需19字节，实际" + QString::number(len) + "字节）");
                    }
                }
            }

            // 若不是指定二进制组包，尝试解析文本格式数据
            if (!isBinaryPacket) {
                // 尝试以字符串形式显示
                QString textData = QString::fromUtf8(rawData);
                if (!textData.isEmpty()) {
                    // 尝试解析文本格式数据
                    PositionData parsedData = DataPacket_parsing(textData);
                    if (parsedData.longitude != -1 && parsedData.latitude != -1) {
                        data = parsedData;
                        ui->textEdit_Network->append("UDP客户端 " + senderAddress.toString() + ":" + QString::number(senderPort) + "（文本数据解析成功）：经度=" + QString::number(data.longitude, 'f', 5) + "，纬度=" + QString::number(data.latitude, 'f', 5));
                    } else {
                        // 纯二进制非文本数据，以十六进制显示
                        textData = "0x" + rawData.toHex(' ').toUpper();
                        ui->textEdit_Network->append("UDP客户端 " + senderAddress.toString() + ":"
                                                     + QString::number(senderPort) + "（原始数据）：" + textData);
                    }
                } else {
                    // 纯二进制非文本数据，以十六进制显示
                    textData = "0x" + rawData.toHex(' ').toUpper();
                    ui->textEdit_Network->append("UDP客户端 " + senderAddress.toString() + ":"
                                                 + QString::number(senderPort) + "（原始数据）：" + textData);
                }
            }

            // 解析有效时执行后续操作
            if (data.longitude != -1 && data.latitude != -1) {
                data.source = PositionData::Network;
                positionCache.append(data);
                ui->lineEdit_longitude->setText(QString::number(data.longitude, 'f', 5));
                ui->lineEdit_latitude->setText(QString::number(data.latitude, 'f', 5));
                Network_To_Serial(data);
            }
        } else {
            ui->textEdit_Network->append("UDP接收失败：" + udpSocket->errorString());
        }
    }
}

// 获取远程主机的地址和端口
bool Widget::parseHostAddress(const QString& input, QHostAddress& address, quint16& port)
{
    QStringList parts = input.split(':');
    if (parts.size() == 2) {
        address.setAddress(parts[0]);
        bool ok;
        port = parts[1].toUShort(&ok);
        return ok;
    }
    return false;
}

// 网口数据转发到串口
void Widget::Network_To_Serial(const PositionData &data)
{
    // 检查自动发送条件（checkBox_AutoSendBin 勾选时转发）
    if (ui->checkBox_AutoSendBin->isChecked()) {
        // 构造串口发送的文本格式（$AE,经度,纬度\r\n）
        QString serialData = QString("$AE,%1,%2\r\n")
                                 .arg(data.longitude, 0, 'f', 5)  // 经度保留5位小数
                                 .arg(data.latitude , 0, 'f', 5); // 纬度保留5位小数

        // 通过串口发送
        if (serialPort && serialPort->isOpen()) {
            serialPort->write(serialData.toUtf8());
            if (serialPort->waitForBytesWritten(1000)) {
                if (ui->checkBox_getReceiveTime->checkState() == Qt::Checked) {
                    ui->textEdit_Network->append(QDateTime::currentDateTime().toString("【yyyy-MM-dd HH:mm:ss.zzz】"));
                }
                ui->textEdit_Receive->append("网口数据：" + serialData);
            } else {
                ui->textEdit_Network->append("转发串口失败：" + serialPort->errorString());
            }
        } else {
            ui->textEdit_Network->append("串口未打开，无法转发");
        }
    }
}

//网口发送
void Widget::on_pushButton_NetSend_clicked()
{
    if (ui->comboBox_comProtocol->currentText() == "TCP") {
        QList<QTcpSocket*> tcpClients = tcpServer->findChildren<QTcpSocket*>();
        for(QTcpSocket* tcpClient : qAsConst(tcpClients))//循环给每一个客户端发送
            tcpClient->write(ui->lineEdit_Send->text().toStdString().c_str());
        ui->label_NetState->setText("TCP Send OK!");
    }
    else if (ui->comboBox_comProtocol->currentText() == "UDP") {
        QHostAddress targetAddress;
        quint16 targetPort;
        if (parseHostAddress(ui->lineEdit_DistanceHost->text(), targetAddress, targetPort)) {
            udpSocket->writeDatagram(ui->lineEdit_Send->text().toUtf8(), targetAddress, targetPort);
            ui->label_NetState->setText("UDP Send OK!");
        }
        else {
            ui->textEdit_Network->append("无效的远程主机地址和端口");
        }
    }
}

//网口开关
void Widget::on_pushButton_Close_Or_Open_Listen_clicked(bool checked)
{
    if(checked){
        if (ui->comboBox_comProtocol->currentText() == "TCP") {
            if(!tcpServer->listen(QHostAddress(ui->comboBox_IP_Addr->currentText()),
                                   ui->lineEdit_networkPort->text().toUInt()))
            {
                QMessageBox MessageBox;
                QIcon *icon = new QIcon("D:/Code/QT/BeidouDataProcessing/icon/Error.png");
                MessageBox.setWindowIcon(*icon);
                MessageBox.setWindowTitle("错误");
                MessageBox.setText("监听失败，端口可能被占用");
                MessageBox.exec();
                return;
            }
            ui->pushButton_Close_Or_Open_Listen->setText("停止监听");
            ui->comboBox_comProtocol->setEnabled(false);
            ui->comboBox_IP_Addr->setEnabled(false);
            ui->lineEdit_networkPort->setEnabled(false);
            ui->comboBox_Client->setEnabled(true);
            ui->pushButton_DisconnectClient->setEnabled(true);
            ui->pushButton_NetSend->setEnabled(true);
        }
        else if (ui->comboBox_comProtocol->currentText() == "UDP") {
            // 关闭可能已经绑定的UDP套接字
            if (udpSocket->state() != QAbstractSocket::UnconnectedState) {
                udpSocket->close();
            }
            // 绑定新的UDP套接字
            quint16 port = ui->lineEdit_networkPort->text().toUInt();
            if (!udpSocket->bind(QHostAddress(ui->comboBox_IP_Addr->currentText()), port)) {
                QMessageBox::critical(this, "错误", "UDP 绑定失败：" + udpSocket->errorString());
                return;
            }
            ui->textEdit_Network->append("UDP 已绑定端口，等待接收数据...");
            ui->pushButton_Close_Or_Open_Listen->setText("停止监听");
            ui->comboBox_comProtocol->setEnabled(false);
            ui->comboBox_IP_Addr->setEnabled(false);
            ui->lineEdit_networkPort->setEnabled(false);
            ui->pushButton_NetSend->setEnabled(true);
        }

    }
    else{
        if (ui->comboBox_comProtocol->currentText() == "TCP") {
            QList<QTcpSocket*> tcpSocketClients = tcpServer->findChildren<QTcpSocket*>();

            //循环将每一个客户端都断开连接
            for(QTcpSocket* SocketClient : qAsConst(tcpSocketClients))
                SocketClient->close();

            tcpServer->close();
            ui->pushButton_Close_Or_Open_Listen->setText("开始监听");
            ui->comboBox_comProtocol->setEnabled(true);
            ui->comboBox_IP_Addr->setEnabled(true);
            ui->lineEdit_networkPort->setEnabled(true);
            ui->pushButton_NetSend->setEnabled(false);
            ui->comboBox_Client->setEnabled(false);
            ui->pushButton_DisconnectClient->setEnabled(false);
        }
        else if (ui->comboBox_comProtocol->currentText() == "UDP") {
            udpSocket->close();
            ui->pushButton_Close_Or_Open_Listen->setText("开始监听");
            ui->comboBox_comProtocol->setEnabled(true);
            ui->comboBox_IP_Addr->setEnabled(true);
            ui->lineEdit_networkPort->setEnabled(true);
            ui->pushButton_NetSend->setEnabled(false);
        }
    }
}

// 刷新可用IP地址
void Widget::reflash_IP_Port(){
    ui->comboBox_IP_Addr->clear(); // 清空旧列表
    QList<QHostAddress> addressList = QNetworkInterface::allAddresses();
    for(const QHostAddress &address : qAsConst(addressList)){
        //将IPv6协议的地址筛选出去，只保留IPv4协议的地址
        if(address.protocol() == QAbstractSocket::IPv4Protocol){
            ui->comboBox_IP_Addr->addItem(address.toString());
        }
    }
    ui->label_NetState->setText("NetAss Reflash OK!");
}

//清空网口位置信息
void Widget::on_pushButton_ClearNet_clicked()
{
    // 遍历缓存列表，保留网口数据，移除串口数据
    QMutableListIterator<PositionData> iter(positionCache);
    while (iter.hasNext()) {
        if (iter.next().source == PositionData::Network) {
            iter.remove(); // 移除串口数据
        }
    }
    // 同时清空界面上的串口接收记录（如textEdit_Receive）
    ui->textEdit_Network->clear();
}

//网口状态转换提示(待完善)
void Widget::stateChanged_Handler(QAbstractSocket::SocketState socketState){
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState:
        ClientDisconnected();
        ui->textEdit_Network->append("客户端断开连接");
        break;
    case QAbstractSocket::HostLookupState:
        break;
    case QAbstractSocket::ConnectingState:
        break;
    case QAbstractSocket::ConnectedState:
        break;
    case QAbstractSocket::BoundState:
        break;
    case QAbstractSocket::ClosingState:
        break;
    case QAbstractSocket::ListeningState:
        break;
    default:
        break;
    }
}

// 主动断开客户端
void Widget::on_pushButton_DisconnectClient_clicked()
{
    // 获取当前选中的客户端标识
    QString selectedClient = ui->comboBox_Client->currentText();
    if (clientMap.contains(selectedClient)) {
        QTcpSocket *clientSocket = clientMap[selectedClient];
        clientSocket->disconnectFromHost(); // 主动断开连接
        // 也可以加上等待断开完成的逻辑，比如：
        if (clientSocket->state() != QTcpSocket::UnconnectedState) {
            clientSocket->waitForDisconnected(1000); // 等待 1 秒
        }
    }
}

// 客户端断开时更新comboBox_Client
void Widget::ClientDisconnected()
{
    QTcpSocket *clientSocket = qobject_cast<QTcpSocket*>(sender());
    if (clientSocket) {
        QString clientKey = clientSocket->peerAddress().toString() + ":" +
                            QString::number(clientSocket->peerPort());

        // 从comboBox_Client与 map 中移除
        clientMap.remove(clientKey);
        int index = ui->comboBox_Client->findText(clientKey);
        if (index != -1) {
            ui->comboBox_Client->removeItem(index);
        }

        // 延迟销毁 socket
        clientSocket->deleteLater();
    }
}

/*串口调试助手*/
//串口接收
void Widget::Serial_readyToRead()
{
    if(ui->checkBox_getReceiveTime->checkState() == Qt::Checked){                                         //如果勾选接收时间检查框
        ui->textEdit_Receive->append(QDateTime::currentDateTime().toString("【yyyy-MM-dd HH:mm:ss.zzz】"));//则在接收数据前打上时间戳
    }
    QString reMessage = QString::fromUtf8(serialPort->readAll());
    ui->textEdit_Receive->append(reMessage);

    PositionData data = DataPacket_parsing(reMessage);
    if (data.longitude != -1 && data.latitude != -1) { // 判断解析有效
        data.source = PositionData::Serial; // 标记位置数据来源（串口）
        positionCache.append(data); // 存入缓存
        //更新UI显示
        ui->lineEdit_longitude->setText(QString::number(data.longitude, 'f', 5));
        ui->lineEdit_latitude ->setText(QString::number(data.latitude, 'f', 5));

        //串口接收到经纬度，再将经纬度以二进制组包的方式通过TCP或UDP发送出去
        if(ui->checkBox_AutoSendBin->isChecked()){//如果自动发送组包被勾选
            if (ui->comboBox_comProtocol->currentText() == "TCP") {
                // TCP转发逻辑
                if(tcpServer->isListening()) {
                    if (!clientMap.isEmpty()) {
                        QByteArray binaryData = packBinaryData(data.longitude, data.latitude);
                        sendTcpData(binaryData); // 发送二进制数据
                        if(ui->checkBox_getReceiveTime->checkState() == Qt::Checked){
                            ui->textEdit_Network->append(QDateTime::currentDateTime().toString("【yyyy-MM-dd HH:mm:ss.zzz】"));
                        }
                        ui->textEdit_Network->append("TCP转发二进制数据（长度：" + QString::number(binaryData.size()) + "字节）");
                    }
                    else {
                        ui->textEdit_Network->append("未连接TCP客户端，无法发送数据");
                    }
                }
                else{
                    ui->textEdit_Network->append("TCP端口未启用");
                }
            }
            else if (ui->comboBox_comProtocol->currentText() == "UDP") {
                // UDP转发逻辑
                // 解析远程主机地址和端口
                QHostAddress targetAddress;
                quint16 targetPort;
                if (parseHostAddress(ui->lineEdit_DistanceHost->text(), targetAddress, targetPort)) {
                    // 构造UDP发送的二进制数据包
                    QByteArray binaryData = packBinaryData(data.longitude, data.latitude);

                    // 通过UDP发送
                    qint64 bytesWritten = udpSocket->writeDatagram(binaryData, targetAddress, targetPort);
                    if (bytesWritten > 0) {
                        if(ui->checkBox_getReceiveTime->checkState() == Qt::Checked){
                            ui->textEdit_Network->append(QDateTime::currentDateTime().toString("【yyyy-MM-dd HH:mm:ss.zzz】"));
                        }
                        ui->textEdit_Network->append("UDP转发二进制数据（长度：" + QString::number(binaryData.size()) + "字节）");
                    } else {
                        ui->textEdit_Network->append("UDP转发失败：" + udpSocket->errorString());
                    }
                } else {
                    ui->textEdit_Network->append("无效的UDP远程地址，无法转发");
                }
            }
        }
    }
}

//串口发送
void Widget::on_pushButton_SerialSend_clicked()
{
    serialPort->write(ui->lineEdit_Send->text().toUtf8());
    ui->label_SerialState->setText("Serial Sent OK!");
}

//串口开关
void Widget::on_pushButton_Close_Or_Open_Serial_clicked(bool checked)
{
    //串口关闭时，既checked=flase时
    if(checked){
        //1.选择端口号
        serialPort->setPortName(ui->comboBox_SerialPort->currentText());
        //2.配置波特率
        serialPort->setBaudRate(ui->comboBox_BaudR->currentText().toInt());
        //3.配置数据位
        serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_DataB->currentText().toInt()));
        //4.配置校验位
        switch(ui->comboBox_CheckB->currentIndex()){
        case 0:
            serialPort->setParity(QSerialPort::NoParity);break;
        case 1:
            serialPort->setParity(QSerialPort::EvenParity);break;
        case 2:
            serialPort->setParity(QSerialPort::OddParity);break;
        case 3:
            serialPort->setParity(QSerialPort::SpaceParity);break;
        case 4:
            serialPort->setParity(QSerialPort::MarkParity);break;
        default:
            serialPort->setParity(QSerialPort::UnknownParity);break;
        }
        //5.配置停止位
        serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_StopB->currentText().toUInt()));
        //6.配置流控
        if(ui->comboBox_FlowControl->currentText() == "None"){
            serialPort->setFlowControl(QSerialPort::NoFlowControl);
        }

        //7.打开串口
        if(serialPort->open(QIODevice::ReadWrite)){
            SerialNum = ui->comboBox_SerialPort->currentText();
            ui->label_SerialState->setText(SerialNum + " Open OK!");
            ui->pushButton_Close_Or_Open_Serial->setText("关闭串口");
            //打开串口后禁用Group控件，既不允许修改串口值
            ui->groupBox_DownLeft->setEnabled(false);
            ui->pushButton_SerialSend->setEnabled(true);
            ui->checkBox_SendInTime->setEnabled(true);
        }
        else{
            //打开失败后将按钮状态重置
            ui->pushButton_Close_Or_Open_Serial->setChecked(false);

            QMessageBox MessageBox;
            QIcon *icon = new QIcon("D:/Code/QT/BeidouDataProcessing/icon/Error.png");
            MessageBox.setWindowIcon(*icon);
            MessageBox.setWindowTitle("错误");
            MessageBox.setText("打开串口失败，串口可能被占用或拔出");
            MessageBox.exec();
        }
    }
    //串口打开时，既checked=true时
    else{
        serialPort->close();
        ui->label_SerialState->setText(SerialNum + " Close OK!");
        SerialNum = "";
        ui->pushButton_Close_Or_Open_Serial->setText("打开串口");

        ui->groupBox_DownLeft->setEnabled(true);
        ui->pushButton_SerialSend->setEnabled(false);

        ui->checkBox_SendInTime->setEnabled(false);
        ui->checkBox_SendInTime->setCheckState(Qt::Unchecked);
        timer->stop();
    }
}

//刷新可用串口号
void Widget::refresh_SerialPorts()
{
    ui->comboBox_SerialPort->clear(); // 清空旧列表
    QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo &port : qAsConst(ports)) {
        ui->comboBox_SerialPort->addItem(port.portName());
    }
    //刷新状态显示
    ui->label_SerialState->setText("Serial Reflash OK!");
}

//清空串口接收
void Widget::on_pushButton_ClearSerial_clicked()
{
    // 遍历缓存列表，保留网口数据，移除串口数据
    QMutableListIterator<PositionData> iter(positionCache);
    while (iter.hasNext()) {
        if (iter.next().source == PositionData::Serial) {
            iter.remove(); // 移除串口数据
        }
    }
    // 同时清空界面上的串口接收记录（如textEdit_Receive）
    ui->textEdit_Receive->clear();
}

//定时发送
void Widget::on_checkBox_SendInTime_clicked(bool checked)
{
    //如果勾选定时发送
    if(checked){
        ui->pushButton_SerialSend->setEnabled(false);
        ui->lineEdit_Send->setEnabled(false);
        ui->lineEdit_Time->setEnabled(false);
        ui->checkBox_AutoSendBin->setEnabled(false);
        ui->checkBox_SendNewLine->setEnabled(false);

        timer->start(ui->lineEdit_Time->text().toUInt());//计时开始
    }
    //若未勾选定时发送
    else{
        timer->stop();                                   //计时停止

        ui->pushButton_SerialSend->setEnabled(true);
        ui->lineEdit_Send->setEnabled(true);
        ui->lineEdit_Time->setEnabled(true);
        ui->checkBox_AutoSendBin->setEnabled(true);
        ui->checkBox_SendNewLine->setEnabled(true);
    }
}

// 解包函数：将数据包拆解并返回经纬度数据
PositionData Widget::DataPacket_parsing(const QString& reMessage)
{
    PositionData data;
    data.longitude = -1;
    data.latitude = -1;
    data.timestamp = QDateTime();

    // 移除末尾的\r\n换行符
    QString processedMsg = reMessage;
    if (processedMsg.endsWith("\r\n"))
        processedMsg.chop(2); // 移除末尾2个字符（\r和\n）
    else if (processedMsg.endsWith("\r") || processedMsg.endsWith("\n"))
        processedMsg.chop(1); // 处理单个换行符的情况
    else if (processedMsg.endsWith("\\r\\n")) {
        processedMsg.chop(6); // 移除末尾 4 个字符（\\r\\n ）
    }
    // qDebug() << "原始数据:" << reMessage << "处理后:" << processedMsg;

    // 校验数据头部和长度
    if (processedMsg.length() >= 4) {
        QString head = processedMsg.left(4);
        if (head == "$AE,") {
            // 提取经纬度内容（从第4位开始）
            QString content = processedMsg.mid(4).trimmed(); // 移除首尾空格
            QStringList parts = content.split(',');

            // 校验分割结果
            if (parts.size() >= 2) {
                bool okLon, okLat;
                double lon = parts[0].toDouble(&okLon);
                double lat = parts[1].toDouble(&okLat);

                if (okLon && okLat) {
                    // 解析成功
                    ui->lineEdit_longitude->setText(QString::number(lon, 'f', 5));
                    ui->lineEdit_latitude->setText(QString::number(lat, 'f', 5));
                    data.longitude = lon;
                    data.latitude = lat;
                    data.timestamp = QDateTime::currentDateTime();
                } else {
                    ui->textEdit_Receive->append("经纬度转换失败（非数字格式）");
                }
            } else {
                ui->textEdit_Receive->append("数据分割失败，格式应为 $AE,经度,纬度\\r\\n");
            }
        } else {
            ui->textEdit_Receive->append("数据头部错误，应为 $AE, ");
        }
    } else {
        ui->textEdit_Receive->append("数据长度不足，无法解析（至少需包含$AE,xxx,yyy）");
    }
    return data;
}

// 组包函数：按格式生成二进制数据并返回
QByteArray Widget::packBinaryData(double lon, double lat)
{
    QByteArray binaryData;
    QDataStream stream(&binaryData, QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::BigEndian); // 符合网络字节序要求

    // 指定格式组包
    quint16 identifier = 0xAABB; // 识别字（2字节Short）
    stream << identifier;
    stream << lon; // 经度                （8字节Double）
    stream << lat; // 纬度                （8字节Double）
    char reserve = 0x00; // 保留字节       （1字节Char）
    stream.writeRawData(&reserve, 1);

    return binaryData; // 返回组好的二进制数据
}

// 发送函数：接收二进制数据并通过TCP发送
void Widget::sendTcpData(const QByteArray& data)
{
    QList<QTcpSocket*> clients = tcpServer->findChildren<QTcpSocket*>();
    foreach (QTcpSocket* client, clients) {
        if (client->state() == QAbstractSocket::ConnectedState) {
            client->write(data); // 使用返回的binaryData发送
        }
    }
}

// 保存位置信息至指定路径的txt文件中
void Widget::on_pushButton_SaveLocation_clicked()
{
    // 若没有位置的缓存数据，则提示用户
    if (positionCache.isEmpty()) {
        QMessageBox::information(this, "提示", "没有可保存的经纬度数据");
        return;
    }

    // 让用户选择保存路径和文件名
    QString filePath = QFileDialog::getSaveFileName(
        this,
        "保存位置信息",
        QDir::homePath() + "/position_data.txt",
        "文本文件 (*.txt);;所有文件 (*)"
        );
    if (filePath.isEmpty()) {
        return; // 用户取消选择
    }

    // 对缓存数据按时间戳排序（升序）
    std::sort(positionCache.begin(), positionCache.end(),
              [](const PositionData& a, const PositionData& b) {
                  return a.timestamp < b.timestamp; // 按时间戳从小到大排序
              }
              );

    // 打开文件并写入数据
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QMessageBox::critical(this, "错误", "无法打开文件：" + file.errorString());
        return;
    }

    QTextStream out(&file);
    out.setCodec("GBK"); // 确保中文等字符正常显示

    // 写入表头（第一行）
    out << "Longitude\tLatitude\t\tTime" << "\n";

    // 写入数据（第二行开始)
    for (const auto& data : qAsConst(positionCache)) {
        // 经度（保留5位小数）、纬度（保留5位小数）、时间（带毫秒）
        out << QString::number(data.longitude, 'f', 5) << "\t"
            << QString::number(data.latitude, 'f', 5) << "\t"
            << data.timestamp.toString("yyyy-MM-dd HH:mm:ss.zzz") << "\n";
    }

    file.close();
}

// 获取当前时间
void Widget::Update_labelTime(){
    QDateTime Time = QDateTime::currentDateTime();
    QString nowTime = Time.toString("yyyy-MM-dd hh:mm:ss dddd");//接收一个格式字符串作为参数，用于指定日期和时间的显示格式
    ui->label_NowTime->setText(nowTime);
}
